package com.wypiwyl.footastic.model;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.wypiwyl.footastic.Direction;
import com.wypiwyl.footastic.FootasticActivity;
import com.wypiwyl.footastic.Player;

import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Toast;

public class Util {

    // declaration log
    private static final String TAG = "Util";

    /*
     * convertit un evenement en un point
     */
    public static Point getPoint(MotionEvent event) {
        return new Point((int) event.getX(), (int) event.getY());
    }

    /*
     * calcule la distance entre 2 points
     */
    public static int getDistance(Point point1, Point point2) {
        return (int) Math.hypot(point1.x - point2.x, point1.y - point2.y);
    }

    /*
     * calcule le delta X entre 2 points
     */
    public static int getDeltaX(Point point1, Point point2) {
        return (int) point1.x - point2.x;
    }

    /*
     * calcule le delta Y entre 2 points
     */
    public static int getDeltaY(Point point1, Point point2) {
        return (int) point1.y - point2.y;
    }
    
    /*
     * calcule la zone d'affichage d'un drawabla a partir de son point centre et des dimensions du drawable
     */
    public static Rect getLayoutDrawable(Point position, int minimumWidth, int minimumHeight) {
        return new Rect(position.x - (minimumWidth / 2), position.y - (minimumHeight / 2), position.x + (minimumWidth / 2), position.y + (minimumHeight / 2));
    }

    public static int getDirection(Point oldPoint, Point newPoint) {
        double dX = newPoint.x - oldPoint.x;
        double dY = newPoint.y - oldPoint.y;
        double dxd;
        if (dX > 0) {
            dxd = dY / dX;
        } else {
            dxd = dX / dY;
        }

        double atan = Math.atan(dxd);

        // declaration de l'angle entre les deux points
        int alpha = 666;

        if (dX >= 0 && dY >= 0) {
            alpha = (int) (Math.toDegrees(atan));
        } else if (dX < 0 && dY >= 0) {
            alpha = (int) (90 - Math.toDegrees(atan));
        } else if (dX < 0 && dY < 0) {
            alpha = (int) (270 - Math.toDegrees(atan));
        } else if (dX >= 0 && dY < 0) {
            alpha = (int) (360 + Math.toDegrees(atan));
        }

        return (int) alpha;
        //        return (int) (Math.toDegrees(atan));
    }

    /*
     * verifie si un point est present dans un cone
     */
    private static boolean isInCone(Point conePoint, int coneRayon, int coneAngleDirection, int coneAngleOuverture, Point checkPoint) {

        Log.i(TAG, ".isInCone" + " - BEGIN");

        boolean check = false;

        // distance entre les deux points
        int distance = getDistance(conePoint, checkPoint);
        // verification de la distance
        if (distance <= coneRayon) {
            // verification que la balle est dans le cone de passe du joueur
            double dX = checkPoint.x - conePoint.x;
            double dY = checkPoint.y - conePoint.y;
            double dxd;
            if (dX > 0) {
                dxd = dY / dX;
            } else {
                dxd = dX / dY;
            }

            double atan = Math.atan(dxd);

            // declaration de l'angle entre les deux points
            int alpha = 666;

            if (dX >= 0 && dY >= 0) {
                alpha = (int) (Math.toDegrees(atan));
            } else if (dX < 0 && dY >= 0) {
                alpha = (int) (90 - Math.toDegrees(atan));
            } else if (dX < 0 && dY < 0) {
                alpha = (int) (270 - Math.toDegrees(atan));
            } else if (dX >= 0 && dY < 0) {
                alpha = (int) (360 + Math.toDegrees(atan));
            }

            // calcul de l'angle avce une rotation en fonction de la direction du joueur
            int angle1 = (int) alpha - coneAngleDirection;
            // calcul de l'angle precedent avec une rotation complete
            int angle2 = angle1 - 360;

            int angleOuverture = (int) coneAngleOuverture / 2;

            check = Math.abs(angle1) <= angleOuverture || Math.abs(angle2) <= angleOuverture;
        }

        Log.i(TAG, ".isInCone" + " - END");

        return check;

    }

    /*
     * verifie si la selection de la chute du ballon est dans le cone
     */
    public static boolean isPassePossible(Player player, Point positionEvent) {

        Log.v(TAG, ".isPassePossible" + " - BEGIN");

        boolean check = isInCone(player.getPosition(), player.getDistancePasse() * 2, player.getDirection(), player.getAnglePasse(), positionEvent);

        Log.v(TAG, ".isPassePossible" + " - END");

        return check;
    }

    /*
     * verifie si l'interception du ballon est possible
     */
    public static boolean isStealPossible(Player player, Point positionBall) {

        Log.v(TAG, ".isStealPossible" + " - BEGIN");

        boolean check = isInCone(player.getPosition(), player.getRayonInterception(), player.getDirection(), player.getAngleInterception(), positionBall);

        Log.v(TAG, ".isStealPossible" + " - END");

        return check;
    }

    /*
     * calcule la nouvelle position du ballon en fonction du point de chute
     * desire et d'autres parametres
     */
    public static Point getPositionPasse(Point oldPositionBall, Point desirePositionBall) {

        Log.v(TAG, ".getPositionPasse" + " - BEGIN");

        // calcul de la distance entre le point de depart et le point selectionne
        int distance = getDistance(oldPositionBall, desirePositionBall);
        Log.v(TAG, ".getPositionPasse" + " - distance : " + distance);
        // calcul du rayon de la chute possible du ballon
        double rayon = Math.sqrt(distance);
        Log.v(TAG, ".getPositionPasse" + " - rayon : " + rayon);

        double rndAngle = Math.random() * 360;
        Log.v(TAG, ".getPositionPasse" + " - rndAngle : " + rndAngle);
        double rndDistance = 0;
        // TODO affiner conf, en fonction des capacites du joueurs ?
        for (int i = 0; i < 4; i++) {
            rndDistance += Math.random() * rayon;
        }
        Log.v(TAG, ".getPositionPasse" + " - rndDistance : " + rndDistance);

        int deltaX = (int) (Math.cos(rndAngle) * rndDistance);
        Log.v(TAG, ".getPositionPasse" + " - deltaX : " + deltaX);
        int deltaY = (int) (Math.sin(rndAngle) * rndDistance);
        Log.v(TAG, ".getPositionPasse" + " - deltaY : " + deltaY);

        Log.v(TAG, ".getPositionPasse" + " - END");

        return new Point(desirePositionBall.x + deltaX, desirePositionBall.y + deltaY);
    }

    public static List<Player> buildSmallTeam(boolean teamOne) {

        List<Player> lPlayer = new ArrayList<Player>();

        int dimensionCase = 42;
        int nbCases = 27;

        int[] tPositionX = { 0, 1, 6, 6, 11, 11 };
        int[] tPositionY = { 0, 7, 6, 9, 5, 10 };

        for (int i = 2; i < 6; i++) {

            Direction direction = null;
            Point position = null;

            if (teamOne) {
                // affectation de la position
                direction = Direction.EAST;
                // calcul de la position
                position = new Point(tPositionX[i] * dimensionCase, tPositionY[i] * dimensionCase);
            } else {
                // affectation de la position
                direction = Direction.WEST;
                // calcul de la position
                position = new Point((nbCases - tPositionX[i]) * dimensionCase, tPositionY[i] * dimensionCase);
            }

            // construction du joueur
            Player player = new Player(teamOne, i, direction, position);
            // ajout du joueur
            lPlayer.add(player);
        }

        return lPlayer;
    }

    public static List<Player> buildBigTeam(boolean teamOne) {

        List<Player> lPlayer = new ArrayList<Player>();

        int dimensionCase = 42;
        int nbCases = 27;

        List<Point> mLPosition = new ArrayList<Point>();
        mLPosition.add(new Point(1, 7));
        mLPosition.add(new Point(5, 6));
        mLPosition.add(new Point(5, 9));
        mLPosition.add(new Point(6, 3));
        mLPosition.add(new Point(6, 12));
        mLPosition.add(new Point(8, 6));
        mLPosition.add(new Point(8, 9));
        mLPosition.add(new Point(10, 2));
        mLPosition.add(new Point(10, 13));
        mLPosition.add(new Point(12, 6));
        mLPosition.add(new Point(12, 9));

        int i = 1;
        
        for (Point position : mLPosition) {
            Direction direction = null;
            Point positionReel;

            if (teamOne) {
                // affectation de la position
                direction = Direction.EAST;
                // calcul de la position
                positionReel = new Point(position.x * dimensionCase, position.y * dimensionCase);
            } else {
                // affectation de la position
                direction = Direction.WEST;
                // calcul de la position
                positionReel = new Point((nbCases - position.x) * dimensionCase, position.y * dimensionCase);
            }

            // construction du joueur
            Player player = new Player(teamOne, i++, direction, positionReel);
            // ajout du joueur
            lPlayer.add(player);
            
        }

        return lPlayer;
    }
    
    public static List<Player> buildTestTeam(boolean teamOne) {

        List<Player> lPlayer = new ArrayList<Player>();

        int dimensionCase = 42;
        int nbCases = 27;

        List<Point> mLPosition = new ArrayList<Point>();
        mLPosition.add(new Point(5, 6));

        int i = 1;
        
        for (Point position : mLPosition) {
            Direction direction = null;
            Point positionReel;

            if (teamOne) {
                // affectation de la position
                direction = Direction.EAST;
                // calcul de la position
                positionReel = new Point(position.x * dimensionCase + dimensionCase / 2, position.y * dimensionCase + dimensionCase / 2);
            } else {
                // affectation de la position
                direction = Direction.WEST;
                // calcul de la position
                positionReel = new Point((nbCases - position.x) * dimensionCase, position.y * dimensionCase);
            }

            // construction du joueur
            Player player = new Player(teamOne, i++, direction, positionReel);
            // ajout du joueur
            lPlayer.add(player);
            
        }

        return lPlayer;
    }

    public static List<Player> buildSmallTeamTEST(boolean teamOne) {

        List<Player> lPlayer = new ArrayList<Player>();

        int dimensionCase = 42;
        int nbCases = 13;

        int[] tPositionX = { 0, 1, 2, 2, 5, 5 };
        int[] tPositionY = { 0, 7, 6, 9, 5, 10 };

        for (int i = 2; i < 6; i++) {

            Direction direction = null;
            Point position = null;

            if (teamOne) {
                // affectation de la position
                direction = Direction.EAST;
                // calcul de la position
                position = new Point(tPositionX[i] * dimensionCase, tPositionY[i] * dimensionCase);
            } else {
                // affectation de la position
                direction = Direction.WEST;
                // calcul de la position
                position = new Point((nbCases - tPositionX[i]) * dimensionCase, tPositionY[i] * dimensionCase);
            }

            // construction du joueur
            Player player = new Player(teamOne, i, direction, position);
            // ajout du joueur
            lPlayer.add(player);
        }

        return lPlayer;
    }
}
